package cn.wp.common.core.web.client;

import cn.hutool.aop.ProxyUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.wp.common.core.WpVar;
import cn.wp.common.core.exception.WpException;
import cn.wp.common.core.util.ApplicationContextUtil;
import cn.wp.common.core.web.WpWebContext;
import cn.wp.common.core.web.annotation.RestServiceConfig;
import cn.wp.common.core.web.client.ServiceRequest;
import cn.wp.common.core.web.client.ServiceTemplate;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpMethod;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.util.MultiValueMap;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.*;
import java.util.List;

/**
 * 服务代理
 * Created by chenyb on 2019/10/17
 */
public class ServiceClientProxy {

    public static <T> T create(Class<?> clazz){
        return ProxyUtil.newProxyInstance(clazz.getClassLoader(),new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                ServiceTemplate serviceTemplate = ApplicationContextUtil.getBean(ServiceTemplate.class);
                Environment env = ApplicationContextUtil.getContext().getBean(Environment.class);

                RestServiceConfig serviceConfig = clazz.getAnnotation(RestServiceConfig.class);
                if(serviceConfig == null){
                    throw new WpException(clazz.getName() + " 未定义RestServiceConfig注解");
                }

                String instanceKey = serviceConfig.configKey() + ".instance-name";
                String loadBalanceKey = serviceConfig.configKey() + ".load-balance";
                String protocolKey = serviceConfig.configKey() + ".instance-protocol";

                String name = env.getProperty(instanceKey);
                boolean loadBalance = env.getProperty(loadBalanceKey,Boolean.class);
                String protocol = env.getProperty(protocolKey);

                ServiceRequest serviceRequest = new ServiceRequest();
                serviceRequest.setLoadBalance(loadBalance);
                serviceRequest.setServiceInstanceName(name);
                serviceRequest.setServiceInstanceProtocol(protocol);
                serviceRequest.setReturnDataOnly(false); // 返回WpResult

                RestServiceConfig methodConfig = method.getAnnotation(RestServiceConfig.class);
                HttpMethod httpMethod = methodConfig.method();
                serviceRequest.setServiceUnitName(methodConfig.path());
                //serviceRequest.setReturnType(new ParameterizedTypeReference<List<Object>>(){});

                // 添加参数
                if(args != null){
                    // 只接受一个MultiValueMap参数
                    if(args != null && args.length > 0 && args[0] instanceof MultiValueMap){
                        serviceRequest.addAll((MultiValueMap<String,Object>)args[0]);
                    }
                    // 参数形式设置序列化泛型
                    //serviceRequest.setReturnType((ParameterizedTypeReference)args[1]);
                }

                // 设置反序列化泛型
                // 动态构造参考：https://www.cnblogs.com/gaomanito/p/9591730.html
                serviceRequest.setReturnType(ParameterizedTypeReference.forType(method.getGenericReturnType()));

                Object result = null;
                if(httpMethod == HttpMethod.GET){
                    result = serviceTemplate.get(serviceRequest);
                }else{
                    result = serviceTemplate.post(serviceRequest);
                }

                return result;
            }
        }, new Class<?>[]{clazz});
    }

}
